﻿using System;
using System.IO;

namespace Ssrtr
{
    
    /// <summary>
    /// Saves audio to wav file.
    /// </summary>
    public static class WaveSaver
    {
        /// <summary>
        /// Saves the wave as a mono audio
        /// </summary>
        /// <param name="samples"></param>
        /// <param name="filename"></param>
        public static void SaveToWave(short[] samples, string filename)
        {
            const short NumberOfChannels = 1; // Save as mono audio
            const short BytesPerSample = 2;   // Make 16bit samples
            const int SamplingRate = 8000;   // Equivalent to 44.1 kHz
            int totalBytes = checked(44 + (samples.Length * BytesPerSample * NumberOfChannels));
            var output = new byte[totalBytes];
            Buffer.BlockCopy(GetBytes(0x46464952), 0, output, 0, 4);  
            Buffer.BlockCopy(GetBytes(totalBytes - 8), 0, output, 4, 4); 
            Buffer.BlockCopy(GetBytes(0x45564157), 0, output, 8, 4);  
            Buffer.BlockCopy(GetBytes(0x20746D66), 0, output, 12, 4); 
            Buffer.BlockCopy(GetBytes(16), 0, output, 16, 4); 
            Buffer.BlockCopy(GetBytes((short)1), 0, output, 20, 2);   
            Buffer.BlockCopy(GetBytes((short)NumberOfChannels), 0, output, 22, 2);   
            Buffer.BlockCopy(GetBytes(SamplingRate), 0, output, 24, 4);   
            Buffer.BlockCopy(GetBytes(SamplingRate * BytesPerSample * NumberOfChannels), 0, output, 28, 4);   
            Buffer.BlockCopy(GetBytes((short)(BytesPerSample * NumberOfChannels)), 0, output, 32, 2);   
            Buffer.BlockCopy(GetBytes((short)(BytesPerSample * 8)), 0, output, 34, 2);  
            Buffer.BlockCopy(GetBytes(0x61746164), 0, output, 36, 4); 
            Buffer.BlockCopy(GetBytes(totalBytes - 44), 0, output, 40, 4); 
            for (var i = 0; i < samples.Length; i++)
            {
                Buffer.BlockCopy(GetBytes(samples[i]), 0, output, (BytesPerSample * i * NumberOfChannels) + 44, BytesPerSample);
            }

            File.WriteAllBytes(filename, output);
        }

      
        /// <summary>
        /// Get bytes from stream
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static byte[] GetBytes(short value)
        {
            if (BitConverter.IsLittleEndian)
            {
                return BitConverter.GetBytes(value);
            }
            else
            {
                return BitConverter.GetBytes((short)((value & 0xFF) << 8 | (value & 0xFF00) >> 8));
            }
        }

        /// <summary>
        /// Get bytes from stream
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static byte[] GetBytes(int value)
        {
            if (BitConverter.IsLittleEndian)
            {
                return BitConverter.GetBytes(value);
            }
            else
            {
                return BitConverter.GetBytes((int)((value & 0xFF) << 24) | (int)((value & 0xFF00) << 8)
                    | (int)((value & 0xFF0000) >> 8) | (int)((value & 0xFF000000) >> 24));
            }
        }
    }
}